package edu.mse.camel.client.session.team;

import java.util.ArrayList;
import java.util.List;

import edu.mse.camel.client.core.session.event.ClientInternalEvent;
import edu.mse.camel.client.eventbus.pubsub.EventManager;

public class TeamList {

	/**
	 * These are members apart from me
	 */
	private List<ITeamMember> members;

	private ITeamMember me;
	
	private boolean isPlayback;

	private static TeamList INSTANCE = new TeamList();

	public static TeamList getInstance() {
		return INSTANCE;
	}

	private TeamList() {
		members = new ArrayList<ITeamMember>();
		isPlayback = false;
	}

	public boolean isPlayback() {
		return isPlayback;
	}

	public void setPlayback(boolean isPlayback) {
		this.isPlayback = isPlayback;
	}

	public List<ITeamMember> getMembers() {
		return members;
	}

	public List<ITeamMember> getSessionTeamMembers() {
		List<ITeamMember> sessionMembers = new ArrayList<ITeamMember>();
		for (ITeamMember aMember : members) {
			if (aMember.getStatus().equals(TEAMMEMBER_STATUS.SESSION)) {
				sessionMembers.add(aMember);
			}
		}
		return sessionMembers;
	}
	
	public List<ITeamMember> getOnlineTeamMembers() {
		List<ITeamMember> onlineMembers = new ArrayList<ITeamMember>();
		for (ITeamMember aMember : members) {
			if (aMember.getStatus().equals(TEAMMEMBER_STATUS.ONLINE)) {
				onlineMembers.add(aMember);
			}
		}
		return onlineMembers;
	}

	public List<ITeamMember> getOfflineTeamMembers() {
		List<ITeamMember> offlineMembers = new ArrayList<ITeamMember>();
		for (ITeamMember aMember : members) {
			if (aMember.getStatus().equals(TEAMMEMBER_STATUS.OFFLINE)) {
				offlineMembers.add(aMember);
			}
		}
		return offlineMembers;
	}

	public ITeamMember getTeamMember(String memberName){
		if (memberName.equals(me.getName())) {
			return me;
		}
		for(ITeamMember aMember : members) {
			if(aMember.getName().equals(memberName))
				return aMember;
		}
		return null;
	}

	public void addTeamMember(List<ITeamMember> newMembers) {
		boolean changed = false;
		List<ITeamMember> addedMembers = new ArrayList<ITeamMember>();
		for (ITeamMember newMember : newMembers) {
			if (!members.contains(newMember)) {
				changed = true;
				members.add(newMember);
				addedMembers.add(newMember);
			}
		}
		if (changed) {
			ClientInternalEvent cie = 
				new	ClientInternalEvent(ClientInternalEvent.ADD_TEAM_MEMBER_MANY, addedMembers);
			EventManager.getInstance().dispatchEventAsynchronous(cie);
		}
	}
	
	public void addTeamMember(ITeamMember member) {
		if (!members.contains(member)) {
			members.add(member);
			ClientInternalEvent cie = 
				new	ClientInternalEvent(ClientInternalEvent.ADD_TEAM_MEMBER, member);
			EventManager.getInstance().dispatchEventAsynchronous(cie);
		} else {
			updateTeamMember(member);
		}
	}

	public void removeTeamMember(ITeamMember member) {
		if (members.contains(member)) {
			members.remove(member);
			ClientInternalEvent cie = 
				new	ClientInternalEvent(ClientInternalEvent.REMOVE_TEAM_MEMBER, member);
			EventManager.getInstance().dispatchEventAsynchronous(cie);
		}
	}
	
	public void updateTeamMember(ITeamMember member) {
		if (members.contains(member)) {
			members.set(members.indexOf(member), member);
			ClientInternalEvent cie = 
				new	ClientInternalEvent(ClientInternalEvent.UPDATE_TEAM_MEMBER_STATUS, member);
			EventManager.getInstance().dispatchEventAsynchronous(cie);
		}
	}

	public void makeFacilitator(String memberID, boolean status) {
		for (ITeamMember aMember : members) {
			if (aMember.getName().equals(memberID)) {
				aMember.setFacilitator(status);
				me.setFacilitator(false);
				ClientInternalEvent cie = 
					new	ClientInternalEvent(ClientInternalEvent.CHANGE_FACILITATOR, aMember);
				EventManager.getInstance().dispatchEventAsynchronous(cie);
				break;
			}
		}		
	}
	
	public void updateTeamMemberList() {

		QueryTeamStatus queryTeamStatusEvent = new QueryTeamStatus();
		EventManager.getInstance().dispatchEventSynchronous(
				queryTeamStatusEvent, true);
		
		members.clear();
		
		List<ITeamMember> tempMembers = queryTeamStatusEvent.getITeamMembers();
		
		if(getMyStatus() == TEAMMEMBER_STATUS.SESSION) {
			updateSessionParticipantList(tempMembers);
		}
		addTeamMember(tempMembers);
	}

	public void updateSessionParticipantList(List<ITeamMember> allTeamMembers) {
		QuerySessionParticipantStatus querySessionParticipantStatus = 
									new QuerySessionParticipantStatus();
		EventManager.getInstance().dispatchEventSynchronous(
				querySessionParticipantStatus, true);
		
		List<ITeamMember> sessionParticipants = querySessionParticipantStatus.getITeamMemberParticipants();
		
		for (ITeamMember aSessionParticipant : sessionParticipants) {
			if (TeamList.getInstance().getMe().getName().equals(
					aSessionParticipant.getName())) {
				getMe().setStatus(TEAMMEMBER_STATUS.SESSION);
				getMe().setFacilitator(aSessionParticipant.isFacilitator());
				getMe().setColor(aSessionParticipant.getColor());
			} else {
				for (ITeamMember aTeamMember : allTeamMembers) {
					if (aTeamMember.equals(aSessionParticipant)) {
						aTeamMember.setStatus(TEAMMEMBER_STATUS.SESSION);
						aTeamMember.setFacilitator(aSessionParticipant.isFacilitator());
						aTeamMember.setColor(aSessionParticipant.getColor());
					}
				}
			}
		}
	}

	public void createSession() {
		me.setStatus(TEAMMEMBER_STATUS.SESSION);
		me.setFacilitator(true);
		ClientInternalEvent cie = 
			new	ClientInternalEvent(ClientInternalEvent.CREATE_SESSION, null);
		EventManager.getInstance().dispatchEventAsynchronous(cie);
		TeamList.getInstance().setPlayback(false);
	}

	public void leaveSession() {
		me.setStatus(TEAMMEMBER_STATUS.ONLINE);
		ClientInternalEvent cie = 
			new	ClientInternalEvent(ClientInternalEvent.LEAVE_SESSION, null);
		EventManager.getInstance().dispatchEventAsynchronous(cie);
	}

	public void logoutFromSession() {
		members.clear();
		me = null;
		ClientInternalEvent cie = 
			new	ClientInternalEvent(ClientInternalEvent.LEAVE_SESSION, null);
		EventManager.getInstance().dispatchEventAsynchronous(cie);
		cie = new ClientInternalEvent(ClientInternalEvent.LOGOUT, null);
		EventManager.getInstance().dispatchEventAsynchronous(cie);
	}

	public ITeamMember getMe() {
		return me;
	}

	public TEAMMEMBER_STATUS getMyStatus() {
		if (me != null) {
			return me.getStatus();
		}
		return TEAMMEMBER_STATUS.OFFLINE;
	}

	public void login(String userName, String email, TEAMMEMBER_STATUS online,
			boolean isFacilitator) {
		createMe(userName, email, online, isFacilitator);
		ClientInternalEvent cie = 
			new	ClientInternalEvent(ClientInternalEvent.LOGIN, me);
		EventManager.getInstance().dispatchEventAsynchronous(cie);
	}
	
	protected void createMe(String userName, String email, TEAMMEMBER_STATUS online,
			boolean isFacilitator) {
		me = new Me(userName, null,
				TEAMMEMBER_STATUS.ONLINE, false);		
		TeamList.getInstance().updateTeamMemberList();
	}

	public void joinSession(Long sessionID) {
		getMe().setStatus(TEAMMEMBER_STATUS.SESSION);
		ClientInternalEvent cie = 
			new ClientInternalEvent(ClientInternalEvent.JOIN_SESSION, sessionID);
		EventManager.getInstance().dispatchEventAsynchronous(cie);
		TeamList.getInstance().updateTeamMemberList();
		TeamList.getInstance().setPlayback(false);
	}

	public void setMyStatus(TEAMMEMBER_STATUS session) {
		me.setStatus(session);
		ClientInternalEvent cie;
		cie = new ClientInternalEvent(ClientInternalEvent.ME_CHANGED, me);
		EventManager.getInstance().dispatchEventAsynchronous(cie);		
	}
}
